package aViewLayer;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.net.URL;

import javax.imageio.ImageIO;

import aModelLayer.Character;
import aModelLayer.Direction;
import aModelLayer.Game;
import aModelLayer.Room;
import aModelLayer.Tile;
import aaGame.RpgGamePanel;
import azServiceLayer.R;
import azServiceLayer.XmlRoomParser;

public class CharacterInRoomView extends View {
	private Character mCharacter;
	private int playerXPos;
	private int playerYPos;
	private XmlRoomParser currentMap;
	private BufferedImage playerSprites;
	private int[] spriteX;
	private int[] spriteY;
	private int spriteWidth;
	private int transitionX;
	private int transitionY;
	private int currentSprite;
	private BufferedImage[] tileSets;
	private int[][][] map;
	private Game mModel;
	private Room room;
	private BufferedImage blackImage;
	private int alpha;
	
	public CharacterInRoomView(Game model){
		mModel = model;
		try {
			playerSprites = ImageIO.read(new File(toURL(R.sprites.testSprite)
					.toURI()));
			blackImage = ImageIO.read(new File(toURL(R.sprites.blackImage)
					.toURI()));
			
			spriteX = new int[12];
			spriteY = new int[12];
			spriteWidth = 34;
			
			for (int y = 0, count = 0; y < 4; y++)
				for (int x = 0; x < 3; x++) {
					spriteX[count] = x * 20;
					spriteY[count] = y * 26;
					count++;
					
				}

			alpha = 0;
		} catch (Exception e) {
			e.printStackTrace();
		}
		//=====================================================
		currentSprite = 7;
	}

	@Override
	public void render(Graphics2D g, RpgGamePanel root) {
		mCharacter = mModel.getCharacter();
		room = mModel.getCurrentRoom();
		currentMap = room.getRoomParser();
		map = currentMap.getLayeredMap();
		tileSets = currentMap.getTileSets();
		playerXPos = mCharacter.tilePosition.x;
		playerYPos = mCharacter.tilePosition.y;
		transitionX = mCharacter.pixelPosition.x;// * currentMap.getTileWidth();
		transitionY = mCharacter.pixelPosition.y; // * currentMap.getTileHeight();
		// TODO Auto-generated method stub
		switch(mCharacter.getFacingDirection()){
		case Direction.RIGHT:
			if((playerXPos*32) - transitionX < 16){
				currentSprite = 4;
			} else {
				if(mCharacter.firstX)
					currentSprite = 3; 
				else
					currentSprite = 5; 
			}
			break;
		case Direction.LEFT:
			if(transitionX - (playerXPos*32) < 16){
				currentSprite = 10;
			}  else {
				if(mCharacter.firstX)
					currentSprite = 9; 
				else
					currentSprite = 11; 
			}
			break;
		case Direction.UP:
			if(transitionY - (playerYPos*32) < 16){
				currentSprite = 1;
			} else {
				if(mCharacter.firstY)
					currentSprite = 0; 
				else
					currentSprite = 2; 
			}
			break;
		case Direction.DOWN:
			if((playerYPos*32) - transitionY < 16){
				currentSprite = 7;
			} else {
				if(mCharacter.firstY)
					currentSprite = 6; 
				else
					currentSprite = 8; 
			}
			break;
		}
		
		
		double zoom = root.getHeight() * 1.5 / root.PANEL_HEIGHT;
	//	playerYPos = mCharacter.tilePosition.y;
	    /*
		 * Bounds the drawn tiles to only the ones being shown on the JPanel.
		 * Previously, the entire map would be drawn, despite only a portion of
		 * it being shown on the screen, which slowed down performance
		 * considerably.
		 */
		int leftBorderTile = playerXPos - (int)((root.getWidth() / 2)/((currentMap.getTileWidth() * zoom)) + 2);
		int rightBorderTile = playerXPos
				+ (int) ((root.getWidth() / 2)
						/ ((currentMap.getTileWidth() * zoom)) + 2);
		int topBorderTile = playerYPos
				- (int) ((root.getHeight() / 2)
						/ ((currentMap.getTileHeight() * zoom)) + 2);
		int bottomBorderTile = playerYPos
				+ (int) ((root.getHeight() / 2)
						/ ((currentMap.getTileHeight() * zoom)) + 2);

		int xBound;
		int yBound;

		/*
		 * The xBound and yBounds are set to zero when the player is at the left
		 * or top edge of the map, respectively. If this wasn't done, the xBound
		 * and yBound would become negative, which would lead to an array out of
		 * bounds exception when they are put into map[][][].
		 */
		if (leftBorderTile >= 0)
			xBound = leftBorderTile;
		else
			xBound = 0;

		if (topBorderTile >= 0)
			yBound = topBorderTile;
		else
			yBound = 0;

		/*
		 * Three nested for loops to go through each tile id in the
		 * map[layer][y][x] array and draw them (with the player's tile position
		 * at the center). The bounds of the for loops are determined by the
		 * xBound and yBound, so only the tiles that are on the screen are
		 * drawn.
		 */
		for (int z = 0; z < currentMap.getLayerNum(); z++) {
			/* Skips drawing if the current layer is the collision layer. */
			if (z == currentMap.getPlayerLayer()) {

				/*
				 * Draws the player's sprite at the center tile on the screen.
				 * Currently, it is set so that the bottom of the sprite is 8
				 * pixels above the bottom of the tile.
				 */
				g.drawImage(
						playerSprites,
						(int) ((root.getWidth() / 2) - ((spriteWidth / 2) * zoom)),
						(int) ((root.getHeight() / 2) - (38 * zoom)),
						(int) ((root.getWidth() / 2) + ((spriteWidth / 2) * zoom)),
						(int) ((root.getHeight() / 2) + (8 * zoom)),
						spriteX[currentSprite], spriteY[currentSprite],
						spriteX[currentSprite] + 20,
						spriteY[currentSprite] + 26, null);

			} else if (z != currentMap.getCollisionLayer() && z != currentMap.getInteractionLayer()) {
				for (int y = yBound; y <= bottomBorderTile
						&& y < currentMap.getRoomHeight(); y++) {
					for (int x = xBound; x <= rightBorderTile
							&& x < currentMap.getRoomWidth(); x++) {
						int index = map[z][y][x];

						/*
						 * Skips drawing if the tile id is -1, which signifies
						 * an empty tile.
						 */
						if (index != -1) {
							/*
							 * Sets the two (x, y) coordinates of where to draw
							 * the tile on the JPanel. Refer to the explanation
							 * of the drawImage(x1, y1, x2, y2, dx1, dy1, dx2,
							 * dy2, observer) method in the Dropbox for more
							 * information.
							 */
							int x1 = (int) ((((x * currentMap.getTileWidth()) - transitionX) * zoom) + ((root
									.getWidth() / 2) - (currentMap
									.getTileWidth() * zoom / 2)));

							int y1 = (int) ((((y * currentMap.getTileHeight()) - transitionY) * zoom) + ((root
									.getHeight() / 2) - (currentMap
									.getTileHeight() * zoom / 2)));

							int x2 = (int) (((((x * currentMap.getTileWidth()) - transitionX) * zoom) + (currentMap
									.getTileWidth() * zoom)) + ((root
									.getWidth() / 2) - (currentMap
									.getTileWidth() * zoom / 2)));

							int y2 = (int) (((((y * currentMap.getTileHeight()) - transitionY) * zoom) + (currentMap
									.getTileHeight() * zoom)) + ((root
									.getHeight() / 2) - (currentMap
									.getTileHeight() * zoom / 2)));

							/*
							 * This for loop determines which tile set is used
							 * for a given tile, and decrements the tile index
							 * by the firstId of the tileSet. e.g.: if the id of
							 * the last tile in the first tileset is 15, then
							 * the id of the first tile of the second tileset is
							 * 16. Assuming the first tile of the second tileset
							 * is needed, the index must be 1 in order for the
							 * drawImage method to be used correctly, so the
							 * index is subracted by tileSetOffset, which in
							 * this case is 15, as the firstIds are subtracted
							 * by 1 in the MapLoader class. The index then
							 * becomes 1, and the tileSetUsed becomes 1 (with 0
							 * being the first tile set).
							 */
							int tileSetUsed = -1;
							int tileSetOffset = 0;
							for (int i = 0; i < tileSets.length; i++) {
								if (index >= currentMap.getTileSetFirstIds()[i]) {
									tileSetUsed++;
									tileSetOffset = currentMap
											.getTileSetFirstIds()[i];
								}
							}
							index -= tileSetOffset;

							/*
							 * This for loop sets the yOffset, which determines
							 * how many rows down the current tile that needs to
							 * be drawn is, and sets the index as if this new
							 * row is the top row. e.g.: if the id of the tile
							 * that needs to be used is 8, and the amount of
							 * tiles in each row is 4, then tile 8 is the fourth
							 * tile on the second row. In this case, yOffset is
							 * set to 1 to go down to the second row, and the
							 * index is subtracted by how many tiles are in each
							 * row (in this case 4), so the new index is 4, with
							 * the yOffset being 1.
							 */
							int yOffset = 0;
							while (index > (tileSets[tileSetUsed].getWidth() / currentMap
									.getTileWidth()) - 1) {
								yOffset++;
								index = index
										- (tileSets[tileSetUsed].getWidth() / currentMap
												.getTileWidth());
							}

							/*
							 * Sets the two (x, y) coordinates of where to get
							 * the tile from the tileset. Refer to the
							 * explanation of the drawImage(x1, y1, x2, y2, dx1,
							 * dy1, dx2, dy2, observer) method in the Dropbox
							 * for more information.
							 */
							int dx1 = index * currentMap.getTileWidth();
							int dy1 = yOffset * currentMap.getTileHeight();
							int dx2 = (index * currentMap.getTileWidth())
									+ currentMap.getTileWidth();
							int dy2 = (yOffset * currentMap.getTileHeight())
									+ currentMap.getTileHeight();

							/*
							 * Draws the tile. Refer to the explanation of the
							 * drawImage(x1, y1, x2, y2, dx1, dy1, dx2, dy2,
							 * observer) method in the Dropbox for more
							 * information.
							 */
							g.drawImage(tileSets[tileSetUsed], x1, y1, x2, y2,
									dx1, dy1, dx2, dy2, null);

						}
					}
				}
			}
		}
		Tile t = room.getCurrentTile(mCharacter.tilePosition);
		if (t.getValue() == Tile.DOOR_TILE){
			if (alpha<=253)
				alpha += 3;
			g.setColor(new Color(0, 0, 0, alpha));
			g.fillRect(0, 0, root.getWidth(), root.getHeight());
		}
		else
		if(t.getValue() == Tile.END_TILE){
			if (alpha<=253)
				alpha += 1;
			g.setColor(new Color(210, 210, 210, alpha));
			g.fillRect(0, 0, root.getWidth(), root.getHeight());
		}else{
			alpha = 0;
		}
		
		//printCollisionMap(); 
	}
	
	/*
	 * Method for printing the collision map data that I used when I was
	 * experiencing bugs. Currently, it's not implemented, but it could be
	 * useful in the future, so I kept it in.
	 */
	public void printCollisionMap() {
		for (int y = 0; y < currentMap.getRoomHeight(); y++) {
			for (int x = 0; x < currentMap.getRoomWidth(); x++) {
				if (x == playerXPos && y == playerYPos)
					System.out.print(" @@ PLAYER @@ ");
				else
					System.out.print(" "+map[currentMap.getCollisionLayer()][y][x]);
				
			}
			System.out.println();
		}

		System.out.println();
	}
	
	private URL toURL(String resource) {
		return this.getClass().getResource(resource);
	}
}
